﻿using System.Collections.Concurrent;
using System.Text;
using System;
using System.Collections.Generic;
using Dapper;
using CommServer.Tasks.Common;
using CommServer.Common.Database;
using CommServer.Cache;
using CommServer.Common;
using Newtonsoft.Json;
using CommServer.Protocol;

namespace CommServer.Tasks
{
    public class Task_DataSave : ATimingTask
    {
        private ConcurrentQueue<dynamic> m_InvDatas = new ConcurrentQueue<dynamic>();
        private ConcurrentQueue<dynamic> m_MeterDatas = new ConcurrentQueue<dynamic>();
        private ConcurrentQueue<dynamic> m_AlarmDatas = new ConcurrentQueue<dynamic>();
        private ConcurrentQueue<dynamic> m_SensorDatas = new ConcurrentQueue<dynamic>();
		private ConcurrentQueue<dynamic> m_InvInfo = new ConcurrentQueue<dynamic>();
        string[] m_MeterFields = new string[] {
                "SystemFrq","Uab","Ubc","Uca","Ia","Ib","Ic",
                "P1","P2","P3","PSum","Q1","Q2","Q3","QSum",
                "S1","S2","S3","SSum","PF1","PF2","PF3","PFSum" ,
                "ZY","FY","ZW","FW","ABSY","JY","ABSW","JW",
                "FLBZY","FLBFY","FLBZW","FLBFW","FLFZY","FLFFY","FLFZW","FLFFW",
                "FLGZY","FLGFY","FLGZW","FLGFW","FLPZY","FLPFY","FLPZW","FLPFW",
                "VNOB","INOB","PXL","QXL","SXL"
        };
       
        public Task_DataSave(DateTime FirstExcuteTime, int Interval, IntervalUnit Unit)
        {
            this.FirstExcuteTime = FirstExcuteTime;
            this.Interval = Interval;
            this.Unit = Unit;

        }

        public void AddInvRealData(dynamic Data)
        {
            if (m_Stop)
            {
                return;
            }
            //由于不知道中自系统什么时候会修改数据，无法自动更新缓存，只能重新加载当前设备信息和其电站信息
            CacheDevices.UpdateCache(Data.RtuSN, Data.Addr);
            m_InvDatas.Enqueue(Data);
        }

        public void AddInvInfo(dynamic invInfo)
        {
            if (m_Stop)
            {
                return;
            }
            m_InvInfo.Enqueue(invInfo);
        }
        public void AddMeterRealData(dynamic Data)
        {
            if (m_Stop)
            {
                return;
            }
            //由于不知道中自系统什么时候会修改数据，无法自动更新缓存，只能重新加载当前设备信息和其电站信息
            CacheDevices.UpdateCache(Data.RtuSN, Data.Addr);
            m_MeterDatas.Enqueue(Data);
        }
        public void AddSensorRealData(dynamic Data)
        {
            if (m_Stop)
            {
                return;
            }
            //由于不知道中自系统什么时候会修改数据，无法自动更新缓存，只能重新加载当前设备信息和其电站信息
            CacheDevices.UpdateCache(Data.RtuSN, Data.Addr);
            m_SensorDatas.Enqueue(Data);
        }
        public void AddAlarmData(List<dynamic> Alarms)
        {
            if (m_Stop)
            {
                return;
            }

            foreach (dynamic Alarm in Alarms)
            {
                //由于不知道中自系统什么时候会修改数据，无法自动更新缓存，只能重新加载当前设备信息和其电站信息
                CacheDevices.UpdateCache(Alarm.RtuSN, Alarm.DevAddr);
                m_AlarmDatas.Enqueue(Alarm);
            }
        }




        private void BatchInsertInvData()
        {
            Dictionary<string, Dictionary<int, List<dynamic>>> InvDatas = new Dictionary<string, Dictionary<int, List<dynamic>>>();
            while (m_InvDatas.TryDequeue(out dynamic V))
            {
                string version = V.Version;
                if(!InvDatas.ContainsKey(version))
                {
                    InvDatas[version] = new Dictionary<int, List<dynamic>>();
                }
                int Key = V.WriteTime.Month;
                if (!InvDatas[version].ContainsKey(Key))
                {
                    InvDatas[version][Key] = new List<dynamic>();
                }
                InvDatas[version][Key].Add(V);
            }
            foreach (var version in InvDatas.Keys)
            {
                foreach (var Key in InvDatas[version].Keys)
                {
                    //插入历史数据
                    string TableName = "inverterp" + InvDatas[version][Key][0].WriteTime.ToString("yyyy_MM");
                    StringBuilder Sql = GetHInvDataSql(TableName, InvDatas[version][Key],version);
                    if ((Sql != null) && (Sql.Length > 0))
                    {
                        DbHelper.Execute(Sql);
                    }

                    //更新实时
                    TableName = "inverterpinstance";
                    Sql = GetHInvDataSql(TableName, InvDatas[version][Key],version);
                    if ((Sql != null) && (Sql.Length > 0))
                    {
                        //Log.Error(Sql.ToString());
                        DbHelper.Execute(Sql);
                    }
                }
            }
        }

        private void BatchInsertMeterData()
        {
            Dictionary<int, List<dynamic>> MeterDatas = new Dictionary<int, List<dynamic>>();
            while (m_MeterDatas.TryDequeue(out dynamic V))
            {
                int Key = V.WriteTime.Month;
                if (!MeterDatas.ContainsKey(Key))
                {
                    MeterDatas[Key] = new List<dynamic>();
                }
                MeterDatas[Key].Add(V);
            }

            foreach (var Key in MeterDatas.Keys)
            {
                //插入历史数据
                string TableName = "meteringdevicep" + MeterDatas[Key][0].WriteTime.ToString("yyyy");
                StringBuilder Sql = GetHMeterDataSql(TableName, MeterDatas[Key]);
                if ((Sql != null) && (Sql.Length > 0))
                {
                    DbHelper.Execute(Sql);
                }
                //更新实时
                TableName = "meteringdevicepinstance";
                Sql = GetHMeterDataSql(TableName, MeterDatas[Key]);
                if ((Sql != null) && (Sql.Length > 0))
                {
                    DbHelper.Execute(Sql);
                }
            }
        }
        private void BatchInsertSensorData()
        {
            Dictionary<int, List<dynamic>> SensorDatas = new Dictionary<int, List<dynamic>>();
            while (m_SensorDatas.TryDequeue(out dynamic V))
            {
                int Key = V.WriteTime.Month;
                if (!SensorDatas.ContainsKey(Key))
                {
                    SensorDatas[Key] = new List<dynamic>();
                }
                SensorDatas[Key].Add(V);
            }

            foreach (var Key in SensorDatas.Keys)
            {
                //插入历史数据
                string TableName = "sensorp" + SensorDatas[Key][0].WriteTime.ToString("yyyy");
                StringBuilder Sql = GetHSensorDataSql(TableName, SensorDatas[Key],"1");
                if ((Sql!=null)&&(Sql.Length > 0))
                {
                    DbHelper.Execute(Sql);
                }
                //更新实时
                TableName = "sensorpinstance";
                Sql = GetHSensorDataSql(TableName, SensorDatas[Key],"1");
                if ((Sql != null) && (Sql.Length > 0))
                {
                    DbHelper.Execute(Sql);
                }
            }
        }

     

        private void BatchInsertAlarmData()
        {
            StringBuilder Sql = new StringBuilder();

            while (m_AlarmDatas.TryDequeue(out dynamic Row))
            {
                string[] Plant = CacheDevices.GetPlantSnUnit(Row.RtuSN, Row.DevAddr);
                if (Plant == null)
                {
                    Log.Error("[BatchInserAlarmData]device not exist in db,rtusn=" + Row.RtuSN + ";addr=" + Row.DevAddr);
                    continue;
                }
                Sql.Append("(");
                Sql.Append("'" + Plant[0] + "',");
                Sql.Append("'" + Plant[1] + "',");
                Sql.Append("'" + Plant[2] + "',");
                Sql.Append(Row.DevAddr + ",");
                Sql.Append(Row.DevType + ",");
                Sql.Append(Row.LogType + ",");
                Sql.Append("'" + Row.LogTime.ToString("yyyy-MM-dd HH:mm:ss") + "',");
                Sql.Append("'" + Row.Note + "',");
                Sql.Append(0);
                Sql.Append("),");
            }
            if (Sql.Length > 0)
            {
                Sql.Remove(Sql.Length - 1, 1);
                Sql.Insert(0, "insert into devicelog (PlantSn,PlantUnit,DevName,DevAddr,DevType,LogType,LogTime,Note,AckStatus) values");
                Sql.Append("  on duplicate key update LogTime = values(LogTime) ");
                DbHelper.Execute(Sql);
            }
        }

        private StringBuilder GetHInvDataSql(string TableName, List<dynamic> Rows,string version)
        {
            List<int> Map = new List<int>();
            List<dynamic> RealDataRows = new List<dynamic>();
            List<dynamic> HisDataRows = new List<dynamic>();
            foreach (var row in Rows)
            {
                if (row.DataType.ToString().Equals("Realdata"))
                {
                    RealDataRows.Add(row);
                }
                else
                {
                    HisDataRows.Add(row);
                }
            }
            List<dynamic> dataRows = (TableName.Equals("inverterpinstance")) ? RealDataRows : Rows;
            if (dataRows.Count == 0)
            {
                return null;
            }
            StringBuilder Sql = new StringBuilder();
            StringBuilder s = new StringBuilder("insert into ");
            s.Append(TableName);
            s.Append(" (PlantSn,PlantUnit,InvTime,DevAddr");
            foreach(int key in ProtocolPV.DataItems[version].Keys)
            {
                if ((key > 289)||(ProtocolPV.DataItems[version][key].FieldName.Length==0))
                    continue;
                Map.Add(key);
                s.Append("," + ProtocolPV.DataItems[version][key].FieldName);
            }
            s.Append(") values");



            foreach (var Row in dataRows)
            {
                var Data = Row.Data;
                string[] Plant = CacheDevices.GetPlantSnUnit(Row.RtuSN, Row.Addr);
                if (Plant == null)
                {

                    //Log.Error(JsonConvert.SerializeObject(Row));
                    Log.Error("[Save Inv Data]device not exist in db,rtusn=" + Row.RtuSN + ";addr=" + Row.Addr);
                    continue;
                }

                Sql.Append('(');
                Sql.Append("'" + Plant[0] + "',");
                Sql.Append("'" + Plant[1] + "',");
                Sql.Append("'" + Row.WriteTime + "',");
                Sql.Append(Row.Addr + ",");
                for(int i=0;i<Map.Count;i++)
                {
                    if ((Data as IDictionary<int, dynamic>).ContainsKey(Map[i]))
                    {
                        Sql.Append(Data[Map[i]] + ",");
                    }
                    else
                    {
                        Sql.Append("null,");
                    }
                }
                Sql.Remove(Sql.Length - 1, 1);

                Sql.Append(')');
                Sql.Append(',');

            }
            if (Sql.Length > 0)
            {//重复数据的处理
                Sql.Remove(Sql.Length - 1, 1);
                Sql.Insert(0, s);
                if (TableName == "inverterpinstance")
                {
                    Sql.Append(" on duplicate key update ");
                    Sql.Append(" InvTime=values(InvTime),");
                    for (int i = 0; i < Map.Count; i++)
                    {
                        Sql.Append(" " + ProtocolPV.DataItems[version][Map[i]].FieldName + "=values(" + ProtocolPV.DataItems[version][Map[i]].FieldName + "),");
                    }
                    Sql.Remove(Sql.Length - 1, 1);
                }
                else
                {
                    Sql.Append(" on duplicate key update ");
                    for (int i = 0; i < Map.Count; i++)
                    {
                        Sql.Append(" " + ProtocolPV.DataItems[version][Map[i]].FieldName + "=values(" + ProtocolPV.DataItems[version][Map[i]].FieldName + "),");
                    }
                    Sql.Remove(Sql.Length - 1, 1);
                }
            }

            return Sql;
        }
       

        private StringBuilder GetHMeterDataSql(string TableName, List<dynamic> Rows)
        {
            Dictionary<int, dynamic> Map = Rows[0].Data as Dictionary<int, dynamic>;
            StringBuilder Sql = new StringBuilder();
            StringBuilder s = new StringBuilder("insert into ");
            s.Append(TableName);
            s.Append(" (PlantSn,PlantUnit,MDPTime,DevAddr");
            for (int i = 501; i <= 552; i++)
            {
                if (Map.ContainsKey(i))
                {
                    s.Append("," + m_MeterFields[i - 501]);
                }

            }
            s.Append(") values");
            foreach (var Row in Rows)
            {
                var Data = Row.Data;
                string[] Plant = CacheDevices.GetPlantSnUnit(Row.RtuSN, Row.Addr);
                if (Plant == null)
                {
                    Log.Error("[Saving Meter Data ]device not exist in db,rtusn=" + Row.RtuSN + ";addr=" + Row.Addr);
                    continue;
                }

                Sql.Append('(');
                Sql.Append("'" + Plant[0] + "',");
                Sql.Append("'" + Plant[1] + "',");
                Sql.Append("'" + Row.WriteTime + "',");
                Sql.Append(Row.Addr + ",");
                for (int i = 501; i <= 552; i++)
                {
                    if (Map.ContainsKey(i))
                    {
                        Sql.Append(Data[i] + ",");
                    }
                }
                Sql.Remove(Sql.Length - 1, 1);

                Sql.Append(')');
                Sql.Append(',');

            }
            if (Sql.Length > 0)
            {
                Sql.Remove(Sql.Length - 1, 1);
                Sql.Insert(0, s);
                if (TableName == "meteringdevicepinstance")
                {
                    Sql.Append(" on duplicate key update ");
                    Sql.Append(" MDPTime=values(MDPTime),");
                    for (int i = 501; i <= 552; i++)
                    {
                        if (Map.ContainsKey(i))
                        {
                            Sql.Append(" " + m_MeterFields[i - 501] + "=values(" + m_MeterFields[i - 501] + "),");
                        }
                    }
                    Sql.Remove(Sql.Length - 1, 1);
                }
            }

            return Sql;
        }
        private StringBuilder GetHSensorDataSql(string TableName, List<dynamic> Rows,string version)
        {
            List<int> Map = new List<int>();
            for (int i = 410; i <= 452; i++)
            {
                if (ProtocolPV.DataItems[version][i].FieldName.Length>0)
                {
                    Map.Add(i);
                }
            }
            StringBuilder Sql = new StringBuilder();
            


            StringBuilder s = new StringBuilder("insert into ");
            s.Append(TableName);
            s.Append(" (PlantSn,PlantUnit,nDate,DevAddr");
            for (int i = 410; i <= 452; i++)
            {
                if (Map.Contains(i))
                {
                    s.Append("," + ProtocolPV.DataItems[version][i].FieldName);
                }
            }
            s.Append(") values");
            foreach (var Row in Rows)
            {
                var Data = Row.Data;
                string[] Plant = CacheDevices.GetPlantSnUnit(Row.RtuSN, Row.Addr);
                if (Plant == null)
                {
                    Log.Error("[Saving Sensor Data ]device not exist in db,rtusn=" + Row.RtuSN + ";addr=" + Row.Addr);
                    continue;
                }

                Sql.Append('(');
                Sql.Append("'" + Plant[0] + "',");
                Sql.Append("'" + Plant[1] + "',");
                Sql.Append("'" + Row.WriteTime + "',");
                Sql.Append(Row.Addr + ",");
                for (int i = 0; i < Map.Count; i++)
                {
                    if ((Data as IDictionary<int, dynamic>).ContainsKey(Map[i]))
                    {
                        Sql.Append(Data[Map[i]] + ",");
                    }
                    else
                    {
                        Sql.Append("null,");
                    }
                }
                Sql.Remove(Sql.Length - 1, 1);

                Sql.Append(')');
                Sql.Append(',');

            }
            if (Sql.Length > 0)
            {//重复数据的处理
                Sql.Remove(Sql.Length - 1, 1);
                Sql.Insert(0, s);
                if (TableName == "sensorpinstance")
                {
                    Sql.Append(" on duplicate key update ");
                    Sql.Append(" nDate=values(nDate),");
                    for (int i = 0; i < Map.Count; i++)
                    {
                        Sql.Append(" " + ProtocolPV.DataItems[version][Map[i]].FieldName + "=values(" + ProtocolPV.DataItems[version][Map[i]].FieldName + "),");
                    }
                    Sql.Remove(Sql.Length - 1, 1);
                }
                else
                {
                    Sql.Append(" on duplicate key update ");
                    for (int i = 0; i < Map.Count; i++)
                    {
                        Sql.Append(" " + ProtocolPV.DataItems[version][Map[i]].FieldName + "=values(" + ProtocolPV.DataItems[version][Map[i]].FieldName + "),");
                    }
                    Sql.Remove(Sql.Length - 1, 1);
                }
            }

            return Sql;
        }
        public override void Excute()
        {
            //批量插入逆变器数据
            if (!m_InvDatas.IsEmpty)
            {
                try
                {
                    BatchInsertInvData();
                }
                catch (Exception ex)
                {
                    Log.Error("save inv data error:" + ex.Message+"|"+ex.Source+"|"+ex.StackTrace);
                }

            }
            //批量插入电表数据
            if (!m_MeterDatas.IsEmpty)
            {
                try
                {
                    BatchInsertMeterData();
                }
                catch (Exception ex)
                {
                    Log.Error("save meter data error:" + ex.Message);
                }

            }
            //批量插入告警
            if (!m_AlarmDatas.IsEmpty)
            {
                try
                {
                    BatchInsertAlarmData();
                }
                catch (Exception ex)
                {
                    Log.Error("save alarm error:" + ex.Message);
                }

            }
            if(!m_InvInfo.IsEmpty)
            {
                try
                {
                    BatchUpdateInvInfo();
                }
                catch(Exception ex)
                {
                    Log.Error("update InvSN Error:" + ex.Message);
                }
            }
            if(!m_SensorDatas.IsEmpty)
            {
                try
                {
                    BatchInsertSensorData();
                }
                catch(Exception ee)
                {
                    Log.Error("save Sensor data error:" + ee.Message + "|" + ee.StackTrace);
                }
            }


        }

        private void BatchUpdateInvInfo()
        {
            string Sql = "";

            while (m_InvInfo.TryDequeue(out dynamic Row))
            {
                Sql = "update deviceinfo set DevName= '" + Row.Pwd + "' where PlantUnit='" + Row.SN + "'";
                DbHelper.Execute(Sql);
            }
        }
    }
}